0%

gateway动态路由

spring cloud gateway 动态路由配置

动态路由的谓词设置

动态路由的谓词 predicates,主要分为以下几个类别:

img

Path

路由匹配,请求path的匹配,动态配置的参数方式如下,构建PredicateDefinition

对应参数的key值为pattern

1
2
3
4
5
6
7
8
9
10
{
"predicates":[
{
"name":"Path",
"args":{
"pattern":"/demo-service/**"
}
}
]
}

对应源码如下

1
2
3
4
5
6
7
8
9
10
11
12
return (exchange) -> {
PathContainer path = PathContainer.parsePath(exchange.getRequest().getURI().getPath());
boolean match = config.pathPattern.matches(path);
traceMatch("Pattern", config.pathPattern.getPatternString(), path, match);
if(match) {
PathMatchInfo uriTemplateVariables = config.pathPattern.matchAndExtract(path);
exchange.getAttributes().put(ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
return true;
} else {
return false;
}
};

Before

路由匹配:当时间在before配置的时间(zoneTime)之前生效

对应的参数:datetime

动态配置如下:

1
2
3
4
5
6
7
8
9
10
{
"predicates":[
{
"name":"Before",
"args":{
"datetime":"2018-12-12T11:14:03.820+08:00[Asia/Shanghai]"
}
}
]
}

对应源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static final String DATETIME_KEY = "datetime";

public BeforeRoutePredicateFactory() {
super(BeforeRoutePredicateFactory.Config.class);
}

public List<String> shortcutFieldOrder() {
return Collections.singletonList("datetime");
}

public Predicate<ServerWebExchange> apply(BeforeRoutePredicateFactory.Config config) {
ZonedDateTime datetime = BetweenRoutePredicateFactory.getZonedDateTime(config.getDatetime());
return (exchange) -> {
ZonedDateTime now = ZonedDateTime.now();
return now.isBefore(datetime);
};
}

After

路由匹配:当时间在After配置的时间(zoneTime)之后生效

对应参数: datetime

动态路由配置:

1
2
3
4
5
6
7
8
9
10
{
"predicates":[
{
"name":"After",
"args":{
"datetime":"2018-12-12T11:14:03.820+08:00[Asia/Shanghai]"
}
}
]
}

对应源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static final String DATETIME_KEY = "datetime";

public AfterRoutePredicateFactory() {
super(AfterRoutePredicateFactory.Config.class);
}

public List<String> shortcutFieldOrder() {
return Collections.singletonList("datetime");
}

public Predicate<ServerWebExchange> apply(AfterRoutePredicateFactory.Config config) {
ZonedDateTime datetime = BetweenRoutePredicateFactory.getZonedDateTime(config.getDatetime());
return (exchange) -> {
ZonedDateTime now = ZonedDateTime.now();
return now.isAfter(datetime);
};
}

Between

路由匹配:当时间在between设置的两个时间点之间,则匹配。

对应参数 datetime1 datetime2

Datetime1 对应的起始时间

Datetime2 对应的结束时间

动态配置:

1
2
3
4
5
6
7
8
9
10
11
{
"predicates":[
{
"name":"Between",
"args":{
"datetime1":"2018-12-12T11:14:03.820+08:00[Asia/Shanghai]",
"datetime2":"2018-12-12T15:14:03.820+08:00[Asia/Shanghai]"
}
}
]
}

对应源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static final String DATETIME1_KEY = "datetime1";
public static final String DATETIME2_KEY = "datetime2";

public BetweenRoutePredicateFactory() {
super(BetweenRoutePredicateFactory.Config.class);
}

public List<String> shortcutFieldOrder() {
return Arrays.asList(new String[]{"datetime1", "datetime2"});
}

public Predicate<ServerWebExchange> apply(BetweenRoutePredicateFactory.Config config) {
ZonedDateTime datetime1 = getZonedDateTime(config.datetime1);
ZonedDateTime datetime2 = getZonedDateTime(config.datetime2);
Assert.isTrue(datetime1.isBefore(datetime2), config.datetime1 + " must be before " + config.datetime2);
return (exchange) -> {
ZonedDateTime now = ZonedDateTime.now();
return now.isAfter(datetime1) && now.isBefore(datetime2);
};
}

路由匹配:在http请求头中包含对应的key和value,则匹配

对应参数:header regexp

header 在Header中设置的key值

regexp key对应的value,支持正则表达式

动态配置:

1
2
3
4
5
6
7
8
9
10
11
{
"predicates":[
{
"name":"Header",
"args":{
"header":"version",
"regexp":"V1.0"
}
}
]
}

对应源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static final String HEADER_KEY = "header";
public static final String REGEXP_KEY = "regexp";

public HeaderRoutePredicateFactory() {
super(HeaderRoutePredicateFactory.Config.class);
}

public List<String> shortcutFieldOrder() {
return Arrays.asList(new String[]{"header", "regexp"});
}

public Predicate<ServerWebExchange> apply(HeaderRoutePredicateFactory.Config config) {
return (exchange) -> {
List<String> values = exchange.getRequest().getHeaders().get(config.header);
if(values != null) {
Iterator var3 = values.iterator();

while(var3.hasNext()) {
String value = (String)var3.next();
if(value.matches(config.regexp)) {
return true;
}
}
}

return false;
};
}

Host

路由匹配:在http请求头中包含对应的Host信息,则匹配

对应参数 pattern

pattern 对应host的正则表达式

动态配置

1
2
3
4
5
6
7
8
9
10
{
"predicates":[
{
"name":"Host",
"args":{
"pattern":"10.88.**"
}
}
]
}

对应源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private PathMatcher pathMatcher = new AntPathMatcher(".");

public HostRoutePredicateFactory() {
super(HostRoutePredicateFactory.Config.class);
}

public void setPathMatcher(PathMatcher pathMatcher) {
this.pathMatcher = pathMatcher;
}

public List<String> shortcutFieldOrder() {
return Collections.singletonList("pattern");
}

public Predicate<ServerWebExchange> apply(HostRoutePredicateFactory.Config config) {
return (exchange) -> {
String host = exchange.getRequest().getHeaders().getFirst("Host");
return this.pathMatcher.match(config.getPattern(), host);
};
}

Method

路由匹配:当请求的Method与配置的method一致,则匹配

对应参数:method

method就是http标准的method内容如GET POST DELETE等

动态配置:

1
2
3
4
5
6
7
8
9
10
{
"predicates":[
{
"name":"Method",
"args":{
"method":"GET"
}
}
]
}

对应源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static final String METHOD_KEY = "method";

public MethodRoutePredicateFactory() {
super(MethodRoutePredicateFactory.Config.class);
}

public List<String> shortcutFieldOrder() {
return Arrays.asList(new String[]{"method"});
}

public Predicate<ServerWebExchange> apply(MethodRoutePredicateFactory.Config config) {
return (exchange) -> {
HttpMethod requestMethod = exchange.getRequest().getMethod();
return requestMethod == config.getMethod();
};
}

路由匹配:当请求的cookie中包含有对应的key和value,则匹配

对应参数:name regexp

name cookie中对应的key值

regexp 与cookie的key对应的value,支持正则表达式

动态配置:

1
2
3
4
5
6
7
8
9
10
11
{
"predicates":[
{
"name":"Cookie",
"args":{
"name":"patrick",
"regexp": "123"
}
}
]
}

相关源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static final String NAME_KEY = "name";
public static final String REGEXP_KEY = "regexp";

public CookieRoutePredicateFactory() {
super(CookieRoutePredicateFactory.Config.class);
}

public List<String> shortcutFieldOrder() {
return Arrays.asList(new String[]{"name", "regexp"});
}

public Predicate<ServerWebExchange> apply(CookieRoutePredicateFactory.Config config) {
return (exchange) -> {
List<HttpCookie> cookies = (List)exchange.getRequest().getCookies().get(config.name);
if(cookies == null) {
return false;
} else {
Iterator var3 = cookies.iterator();

HttpCookie cookie;
do {
if(!var3.hasNext()) {
return false;
}

cookie = (HttpCookie)var3.next();
} while(!cookie.getValue().matches(config.regexp));

return true;
}
};
}

Query

路由匹配:当请求的url对应的parameter的key value与设置的一一对应,则匹配

参数: param regexp

Param url参数的key值

regexp url的key对应的value值,可以为正则表达式

当时配置多个Query的时候,是&运算,如果key不一致,gateway会提示500错,如果value不一致,则提示404错误

动态配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"predicates":[
{
"name":"Query",
"args":{
"param":"patrick",
"regexp": "123"
}
},
{
"name":"Query",
"args":{
"param":"haha",
"regexp": "hehe"
}
}
]
}

相关源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static final String PARAM_KEY = "param";
public static final String REGEXP_KEY = "regexp";

public QueryRoutePredicateFactory() {
super(QueryRoutePredicateFactory.Config.class);
}

public List<String> shortcutFieldOrder() {
return Arrays.asList(new String[]{"param", "regexp"});
}

public Predicate<ServerWebExchange> apply(QueryRoutePredicateFactory.Config config) {
return (exchange) -> {
if(!StringUtils.hasText(config.regexp)) {
return exchange.getRequest().getQueryParams().containsKey(config.param);
} else {
List<String> values = (List)exchange.getRequest().getQueryParams().get(config.param);
Iterator var3 = values.iterator();

String value;
do {
if(!var3.hasNext()) {
return false;
}

value = (String)var3.next();
} while(!value.matches(config.regexp));

return true;
}
};
}

RemoteAddr

路由匹配:当客户端的ip与设置的ip段一致,则匹配

参数 sources

sources 配置客户端的ip地址段 如192.168.1.1/24

动态配置:

1
2
3
4
5
6
7
8
9
10
{
"predicates":[
{
"name":"RemoteAddr",
"args":{
"sources":"192.168.1.1/24"
}
}
]
}

对应源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public Predicate<ServerWebExchange> apply(RemoteAddrRoutePredicateFactory.Config config) {
List<IpSubnetFilterRule> sources = this.convert(config.sources);
return (exchange) -> {
InetSocketAddress remoteAddress = config.remoteAddressResolver.resolve(exchange);
if(remoteAddress != null) {
String hostAddress = remoteAddress.getAddress().getHostAddress();
String host = exchange.getRequest().getURI().getHost();
if(log.isDebugEnabled() && !hostAddress.equals(host)) {
log.debug("Remote addresses didn't match " + hostAddress + " != " + host);
}

Iterator var6 = sources.iterator();

while(var6.hasNext()) {
IpSubnetFilterRule source = (IpSubnetFilterRule)var6.next();
if(source.matches(remoteAddress)) {
return true;
}
}
}

return false;
};
}

动态路由gatewayFilter设置

AddRequestHeader

过滤器功能:网关为请求的header添加key value

参数 name value

name 添加header的key

value 添加header对应key的value

动态配置:

1
2
3
4
5
6
7
8
9
10
11
{
"filters":[
{
"name":"AddRequestHeader",
"args":{
"name":"patrick",
"value":"bar"
}
}
]
}

RemoveRequestHeader

过滤器功能:网关为请求的header抹去key value

参数 name

name 需要抹去的header中的key

动态配置:

1
2
3
4
5
6
7
8
9
10
{
"filters":[
{
"name":"RemoveRequestHeader",
"args":{
"name":"patrick"
}
}
]
}

RemoveResponseHeader

过滤器功能:网关将返回的header的头remove对应的key

参数:name

name 需要抹去的header的key

动态配置:

1
2
3
4
5
6
7
8
9
10
{
"filters":[
{
"name":"RemoveResponseHeader",
"args":{
"name":"patrick"
}
}
]
}

AddResponseHeader

过滤器功能:网关添加ResponseHeader的key和value

参数:name value

name 需要添加在response header的key

value 需要添加在response header的key对应的value

动态配置:

1
2
3
4
5
6
7
8
9
10
{
"filters":[
{
"name":"AddResponseHeader",
"args":{
"name":"patrick"
}
}
]
}

SetResponseHeader

过滤器功能:网关设置ResponseHeader的key和value

参数 name value

name 需要设置在response header的key

value 需要设置在response header的key对应的value

与addResponseHeader的区别,应用官网的原话

This GatewayFilter replaces all headers with the given name, rather than adding. So if the downstream server responded with a X-Response-Foo:1234, this would be replaced with X-Response-Foo:Bar, which is what the gateway client would receive.

重置指定的key value

动态配置:

1
2
3
4
5
6
7
8
9
10
{
"filters":[
{
"name":"SetResponseHeader",
"args":{
"name":"patrick"
}
}
]
}

AddRequestParameter

过滤器功能:网关给请求的url中添加param

参数: name value

动态配置:

1
2
3
4
5
6
7
8
9
10
11
{
"filters":[
{
"name":"AddRequestParameter",
"args":{
"name":"patrick",
"value": "test"
}
}
]
}

RewritePath

过滤器功能:应用请求通过predicate匹配到对应的route后,需要将url进行替换,发送到指定的后端模块

参数: regexp replacement

regexp 需要替换的path的正则表达式

replacement 替换的内容的正则

动态配置:

1
2
3
4
5
6
7
{
"name":"RewritePath",
"args":{
"regexp":"/demo-service/(?<remaining>.*)",
"replacement":"/${remaining}"
}
}

PrefixPath

过滤器功能:请求到具体服务的path时,给path前面加上前缀 prefix

参数:prefix

prefix 给路由目标路径前添加前缀

This will prefix /mypath to the path of all matching requests. So a request to /hello, would be sent to /mypath/hello.

动态配置:

1
2
3
4
5
6
7
8
9
10
{
"filters":[
{
"name":"PrefixPath",
"args":{
"prefix":"/mypath"
}
}
]
}

SetPath

过滤器功能:请求到具体服务的path时,通过template对应的内容对整个uri进行替换

参数:template

template 需要替换掉uri的内容模版

For a request path of /foo/bar, this will set the path to /bar before making the downstream request.

动态配置:

1
2
3
4
5
6
7
8
9
10
{
"filters":[
{
"name":"SetPath",
"args":{
"template":"/mypath"
}
}
]
}

RedirectTo

过滤器功能:设置跳转到三方系统,http的状态码必须为3xx系列。

参数:status url

status 跳转的http状态码,必须是3xx,比如302

url 跳转的地址

动态配置:

1
2
3
4
5
6
7
8
9
10
11
{
"filters":[
{
"name":"RedirectTo",
"args":{
"status": 302,
"url": "http://www.baidu.com"
}
}
]
}